package edu.utd.text.game.controller.parsing;

import java.util.StringTokenizer;

import edu.utd.text.game.controller.commands.BooleanCommand;
import edu.utd.text.game.controller.commands.DropItemCommand;
import edu.utd.text.game.controller.commands.ExamineCommand;
import edu.utd.text.game.controller.commands.GameCommand;
import edu.utd.text.game.controller.commands.LoadGameCommand;
import edu.utd.text.game.controller.commands.MovementCommand;
import edu.utd.text.game.controller.commands.PickupCommand;
import edu.utd.text.game.controller.commands.SaveGameCommand;
import edu.utd.text.game.controller.commands.ShowInventoryCommand;
import edu.utd.text.game.domain.areas.Direction;
import edu.utd.text.game.domain.exceptions.UserInputParseException;

/**
 * The parser can take a string from user input and
 * generate a GameCommand from it.
 * @author troy
 *
 */

public class CommandParser extends AbstractParser {

	public static final CommandParser INSTANCE = new CommandParser();
	
	private CommandParser() {  }
	
	public GameCommand parseInput(String input) 
			throws UserInputParseException 	
	{
		if(!input.isEmpty()) {	
			//try to put the quickest operations first
			try { return parseInputForSaveGame(input);		} catch (UserInputParseException uipx) { ; /*Go on*/ }
			try { return parseInputForLoadGame(input); 		} catch (UserInputParseException uipx) { ; /*Go on*/ }
			try { return parseInputForBoolean(input); 		} catch (UserInputParseException uipx) { ; /*Go on*/ }
			try { return parseInputForShowInventory(input);	} catch (UserInputParseException uipx) { ; /*Go on*/ }
			try { return parseInputForExamine(input);		} catch (UserInputParseException uipx) { ; /*Go on*/ }
			try { return parseInputForMovement(input);		} catch (UserInputParseException uipx) { ; /*Go on*/ }
			try { return parseInputForPickup(input); 		} catch (UserInputParseException uipx) { ; /*Go on*/ }
			try { return parseInputForDropItem(input); 		} catch (UserInputParseException uipx) { ; /*Go on*/ }
		}
		throw new UserInputParseException();
	}
	
	public SaveGameCommand parseInputForSaveGame(String input) 
			throws UserInputParseException
	{
		input = input.trim().toLowerCase();
		if (input.equals("save")) {
			return new SaveGameCommand();
		}
		throw new UserInputParseException();
	}
	
	public LoadGameCommand parseInputForLoadGame(String input) 
			throws UserInputParseException
	{
		input = input.trim().toLowerCase();
		if (input.equals("load")) {
			return new LoadGameCommand();
		}
		throw new UserInputParseException();
	}
	
	public BooleanCommand parseInputForBoolean(String userInput) 
			throws UserInputParseException
	{
		if (userInput.equalsIgnoreCase("yes")) {
			return new BooleanCommand(true);
		}
		if (userInput.equalsIgnoreCase("no")) {
			return new BooleanCommand(false);
		}
		throw new UserInputParseException();
	}
	
	//TODO : Should these commands be singletons or something?  Will they ever be gc'd properly?  We are creating a lot of them.
	public ShowInventoryCommand parseInputForShowInventory(String userInput) 
			throws UserInputParseException
	{
		if (userInput.equalsIgnoreCase("i")
				|| userInput.equalsIgnoreCase("inv")
				|| userInput.equalsIgnoreCase("inventory"))
		{
			return new ShowInventoryCommand();
		}
		throw new UserInputParseException();
	}
	
	/**
	 * Commands related to looking and examining things.
	 */
	public ExamineCommand parseInputForExamine(String userInput)
			throws UserInputParseException 
	{
		StringTokenizer tokenizer = new StringTokenizer(userInput);
		String firstWord = tokenizer.nextToken();
		
		if (firstWord.equalsIgnoreCase("l")
				|| firstWord.equalsIgnoreCase("look")
				|| firstWord.equalsIgnoreCase("examine")
				|| firstWord.equalsIgnoreCase("exam")) {
			ExamineCommand examineCommand = new ExamineCommand();
			if (tokenizer.hasMoreTokens()) {
				examineCommand.setObjectToExamine(tokenizer.nextToken().trim());
			}
			return examineCommand;
		}
		throw new UserInputParseException();
	}
	
	public MovementCommand parseInputForMovement(String userInput)
			throws UserInputParseException
	{
		//NORTH
		if (userInput.equalsIgnoreCase("north")) {
			return new MovementCommand(Direction.NORTH);
		} else if (userInput.equalsIgnoreCase("n")) {
			return new MovementCommand(Direction.NORTH);
		}
		//SOUTH
		if (userInput.equalsIgnoreCase("south")) {
			return new MovementCommand(Direction.SOUTH);
		} else if (userInput.equalsIgnoreCase("s")) {
			return new MovementCommand(Direction.SOUTH);
		}
		//EAST
		if (userInput.equalsIgnoreCase("east")) {
			return new MovementCommand(Direction.EAST);
		} else if (userInput.equalsIgnoreCase("e")) {
			return new MovementCommand(Direction.EAST);
		}
		//WEST
		if (userInput.equalsIgnoreCase("west")) {
			return new MovementCommand(Direction.WEST);
		} else if (userInput.equalsIgnoreCase("w")) {
			return new MovementCommand(Direction.WEST);
		}
		//NORTHEAST
		if (userInput.equalsIgnoreCase("northeast")) {
			return new MovementCommand(Direction.NORTHEAST);
		} else if (userInput.equalsIgnoreCase("ne")) {
			return new MovementCommand(Direction.NORTHEAST);
		}
		//NORTHWEST
		if (userInput.equalsIgnoreCase("northwest")) {
			return new MovementCommand(Direction.NORTHWEST);
		} else if (userInput.equalsIgnoreCase("nw")) {
			return new MovementCommand(Direction.NORTHWEST);
		}
		//SOUTHEAST
		if (userInput.equalsIgnoreCase("southeast")) {
			return new MovementCommand(Direction.SOUTHEAST);
		} else if (userInput.equalsIgnoreCase("se")) {
			return new MovementCommand(Direction.SOUTHEAST);
		}
		//SOUTHWEST
		if (userInput.equalsIgnoreCase("southwest")) {
			return new MovementCommand(Direction.SOUTHWEST);
		} else if (userInput.equalsIgnoreCase("sw")) {
			return new MovementCommand(Direction.SOUTHWEST);
		}
		throw new UserInputParseException();	//if it didn't match any of those, give up.
	}
	
	public PickupCommand parseInputForPickup(String userInput) 
			throws UserInputParseException
	{
		StringTokenizer tokenizer = new StringTokenizer(userInput);
		String firstWord = tokenizer.nextToken();
		if (firstWord.equalsIgnoreCase("get")
			|| firstWord.equalsIgnoreCase("pickup")
			|| ( (firstWord.equalsIgnoreCase("pick")
					&& tokenizer.nextToken().equalsIgnoreCase("up"))
				)) 
		{
			String objectToPickup = "";
			while (tokenizer.hasMoreTokens()) {
				objectToPickup += (" " + tokenizer.nextToken());
			}
			return new PickupCommand(objectToPickup.trim());
		}
		throw new UserInputParseException();
	}
	
	//TODO: Pickup, Drop, and Examine all have similar semantics: VERB [MODIFIER] OBJECT ... maybe we can generalize?
	public DropItemCommand parseInputForDropItem(String userInput) 
			throws UserInputParseException
	{
		StringTokenizer tokenizer = new StringTokenizer(userInput);
		String firstWord = tokenizer.nextToken();
		if(firstWord.equalsIgnoreCase("drop")
			|| firstWord.equalsIgnoreCase("leave"))
		{
			String itemToDrop = "";
			while (tokenizer.hasMoreTokens()) {
				itemToDrop += (" " + tokenizer.nextToken());
			}
			return new DropItemCommand(itemToDrop.trim());
		}
		throw new UserInputParseException();
	}
	

}
